home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / acompchoose.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-20  |  12.0 KB  |  451 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include "VirtualDub.h"
  19.  
  20. #include <string.h>
  21. #include <stdlib.h>
  22.  
  23. #include <windows.h>
  24. #include <mmsystem.h>
  25. #include <mmreg.h>
  26. #include <msacm.h>
  27.  
  28. #include "resource.h"
  29. #include "list.h"
  30. #include "gui.h"
  31.  
  32. ///////////////////////////////////////////////////////////////////////////
  33.  
  34. extern HINSTANCE g_hInst;
  35.  
  36. ///////////////////////////////////////////////////////////////////////////
  37.  
  38. void CopyWaveFormat(WAVEFORMATEX *pDst, const WAVEFORMATEX *pSrc) {
  39.     if (pSrc->wFormatTag == WAVE_FORMAT_PCM)
  40.         memcpy(pDst, pSrc, sizeof(PCMWAVEFORMAT));
  41.     else
  42.         memcpy(pDst, pSrc, sizeof(WAVEFORMATEX) + pSrc->cbSize);
  43. }
  44.  
  45. ///////////////////////////////////////////////////////////////////////////
  46.  
  47. class ACMFormatEntry : public ListNode2<ACMFormatEntry> {
  48. public:
  49.     ACMFORMATDETAILS afd;
  50.     WAVEFORMATEX *pwfex;
  51.     bool fCompatible;
  52.  
  53.     ~ACMFormatEntry();
  54. };
  55.  
  56. ACMFormatEntry::~ACMFormatEntry() {
  57.     freemem(pwfex);
  58. }
  59.  
  60. class ACMTagEntry {
  61. public:
  62.     List2<ACMFormatEntry> formats;
  63.     ACMFORMATTAGDETAILS aftd;
  64.  
  65.     ~ACMTagEntry();
  66. };
  67.  
  68. ACMTagEntry::~ACMTagEntry() {
  69.     ACMFormatEntry *pafe;
  70.  
  71.     while(pafe = formats.RemoveHead())
  72.         delete pafe;
  73. }
  74.  
  75. ///////////////////////////////////////////////////////////////////////////
  76.  
  77. struct ACMEnumeratorData {
  78.     HWND hwndDriverList;
  79.     ACMTagEntry *pate;
  80.     HACMDRIVER had;
  81.     WAVEFORMATEX *pwfex, *pwfexSelect, *pwfexSrc;
  82.     DWORD cbwfex;
  83.     ACMFormatEntry *pFormatSelect;
  84.     ACMTagEntry *pTagSelect;
  85.     bool fAttemptedWeird;
  86. };
  87.  
  88. struct ACMChooserData {
  89.     WAVEFORMATEX *pwfex, *pwfexSrc;
  90. };
  91.  
  92. ///////////////////////////////////////////////////////////////////////////
  93.  
  94. BOOL CALLBACK ACMFormatEnumerator(HACMDRIVERID hadid, LPACMFORMATDETAILS pafd, DWORD dwInstance, DWORD fdwSupport) {
  95.     ACMEnumeratorData *pData = (ACMEnumeratorData *)dwInstance;
  96.     ACMFormatEntry *pafe = new ACMFormatEntry();
  97.  
  98.     if (!pafe) return TRUE;
  99.  
  100.     if (!(pafe->pwfex = (WAVEFORMATEX *)allocmem(sizeof(WAVEFORMATEX) + pafd->pwfx->cbSize))) {
  101.         delete pafe;
  102.         return TRUE;
  103.     }
  104.  
  105.     pafe->afd = *pafd;
  106.  
  107.     memcpy(pafe->pwfex, pafd->pwfx, sizeof(WAVEFORMATEX) + pafd->pwfx->cbSize);
  108.  
  109.     if (!pData->pTagSelect && pData->pwfexSelect && pafd->pwfx->wFormatTag == pData->pwfexSelect->wFormatTag
  110.         && !memcmp(pafd->pwfx, pData->pwfexSelect, sizeof(WAVEFORMATEX)+pafd->pwfx->cbSize)) {
  111.  
  112.         pData->pTagSelect = pData->pate;
  113.         pData->pFormatSelect = pafe;
  114.     }
  115.  
  116.     pafe->fCompatible = true;
  117.  
  118.     if (pData->pwfexSrc) {
  119.         pafe->fCompatible = !acmStreamOpen(NULL, pData->had, pData->pwfexSrc, pafd->pwfx, NULL, 0, 0, ACM_STREAMOPENF_QUERY);
  120.  
  121.         if (pafd->pwfx->nChannels == pData->pwfexSrc->nChannels
  122.             && pafd->pwfx->wBitsPerSample == pData->pwfexSrc->wBitsPerSample
  123.             && pafd->pwfx->nSamplesPerSec == pData->pwfexSrc->nSamplesPerSec)
  124.             pData->fAttemptedWeird = true;
  125.     }
  126.  
  127.     pData->pate->formats.AddTail(pafe);
  128.  
  129.     return TRUE;
  130. }
  131.  
  132. BOOL /*ACMFORMATTAGENUMCB*/ CALLBACK ACMFormatTagEnumerator(HACMDRIVERID hadid, LPACMFORMATTAGDETAILS paftd, DWORD dwInstance, DWORD fdwSupport) {
  133.     ACMEnumeratorData *pData = (ACMEnumeratorData *)dwInstance;
  134.  
  135.     if (paftd->dwFormatTag != WAVE_FORMAT_PCM) {
  136.         int index;
  137.  
  138.         index = guiListboxInsertSortedString(pData->hwndDriverList, paftd->szFormatTag);
  139.  
  140.         if (index != LB_ERR) {
  141.             ACMTagEntry *pate = new ACMTagEntry();
  142.             ACMFORMATDETAILS afd;
  143.  
  144.             pate->aftd = *paftd;
  145.             pData->pate = pate;
  146.  
  147.             memset(&afd, 0, sizeof afd);
  148.             afd.cbStruct = sizeof(ACMFORMATDETAILS);
  149.             afd.pwfx = pData->pwfex;
  150.             afd.cbwfx = pData->cbwfex;
  151.             afd.dwFormatTag = paftd->dwFormatTag;
  152.             pData->pwfex->wFormatTag = paftd->dwFormatTag;
  153.  
  154.             pData->fAttemptedWeird = false;
  155.             acmFormatEnum(pData->had, &afd, ACMFormatEnumerator, dwInstance, ACM_FORMATENUMF_WFORMATTAG);
  156.  
  157.             if (!pData->fAttemptedWeird && pData->pwfexSrc) {
  158.  
  159.                 CopyWaveFormat(pData->pwfex, pData->pwfexSrc);
  160.  
  161.                 pData->pwfex->wFormatTag = paftd->dwFormatTag;
  162.  
  163.                 if (!acmFormatSuggest(pData->had, pData->pwfexSrc, pData->pwfex, pData->cbwfex, ACM_FORMATSUGGESTF_NCHANNELS|ACM_FORMATSUGGESTF_NSAMPLESPERSEC|ACM_FORMATSUGGESTF_WFORMATTAG)) {
  164.                     afd.dwFormatIndex = 0;
  165.                     afd.fdwSupport = 0;
  166.  
  167.                     if (!acmFormatDetails(pData->had, &afd, ACM_FORMATDETAILSF_FORMAT))
  168.                         ACMFormatEnumerator(hadid, &afd, dwInstance, 0);
  169.                 }
  170.             }
  171.  
  172.             SendMessage(pData->hwndDriverList, LB_SETITEMDATA, index, (LPARAM)pate);
  173.         }
  174.     }
  175.  
  176.     return TRUE;
  177. }
  178.  
  179. BOOL /*ACMDRIVERENUMCB*/ CALLBACK ACMDriverEnumerator(HACMDRIVERID hadid, DWORD dwInstance, DWORD fdwSupport) {
  180.     ACMEnumeratorData *pData = (ACMEnumeratorData *)dwInstance;
  181.  
  182.     if (!acmDriverOpen(&pData->had, hadid, 0)) {
  183.         ACMFORMATTAGDETAILS aftd;
  184.  
  185.         memset(&aftd, 0, sizeof aftd);
  186.         aftd.cbStruct = sizeof aftd;
  187.  
  188.         acmFormatTagEnum(pData->had, &aftd, ACMFormatTagEnumerator, dwInstance, 0);
  189.  
  190.         acmDriverClose(pData->had, 0);
  191.     }
  192.  
  193.     return TRUE;
  194. }
  195.  
  196. static void AudioChooseDisplaySpecs(HWND hdlg, WAVEFORMATEX *pwfex) {
  197.     char buf[128];
  198.     int blps;
  199.  
  200.     if (pwfex) {
  201.         if (pwfex->wFormatTag == WAVE_FORMAT_PCM)
  202.             strcpy(buf, "0x0000 (PCM)");
  203.         else
  204.             wsprintf(buf, "0x%04x", pwfex->wFormatTag);
  205.     } else
  206.         buf[0] = 0;
  207.     SetDlgItemText(hdlg, IDC_STATIC_FORMATID, buf);
  208.  
  209.     if (pwfex) wsprintf(buf, "%ld bytes", pwfex->nBlockAlign);
  210.     SetDlgItemText(hdlg, IDC_STATIC_BYTESPERBLOCK, buf);
  211.  
  212.     if (pwfex) wsprintf(buf, "%ld bytes/sec", pwfex->nAvgBytesPerSec);
  213.     SetDlgItemText(hdlg, IDC_STATIC_DATARATE, buf);
  214.  
  215.     if (pwfex) {
  216.         blps = MulDiv(pwfex->nAvgBytesPerSec, 10, pwfex->nBlockAlign);
  217.         wsprintf(buf, "%ld.%c blocks/sec", blps/10, (blps%10)+'0');
  218.     }
  219.     SetDlgItemText(hdlg, IDC_STATIC_GRANULARITY, buf);
  220. }
  221.  
  222. static void AudioChooseShowFormats(HWND hdlg, ACMTagEntry *pTag, bool fShowCompatibleOnly) {
  223.     ACMChooserData *thisPtr = (ACMChooserData *)GetWindowLong(hdlg, DWL_USER);
  224.     HWND hwndListFormats = GetDlgItem(hdlg, IDC_FORMAT);
  225.     int idx;
  226.  
  227.     SendMessage(hwndListFormats, LB_RESETCONTENT, 0, 0);
  228.  
  229.     if (!pTag) {
  230.         AudioChooseDisplaySpecs(hdlg, thisPtr->pwfexSrc);
  231.         return;
  232.     }
  233.  
  234.     AudioChooseDisplaySpecs(hdlg, NULL);
  235.  
  236.     ACMFormatEntry *pFormat = pTag->formats.AtHead(), *pFormat_next;
  237.  
  238.     while(pFormat_next = pFormat->NextFromHead()) {
  239.         char buf[128];
  240.         int band;
  241.  
  242.         if (!fShowCompatibleOnly || pFormat->fCompatible) {
  243.             band = (pFormat->pwfex->nAvgBytesPerSec+1023)/1024;
  244.             wsprintf(buf, "%s\t%dKb/s", pFormat->afd.szFormat, band);
  245.  
  246.             idx = SendMessage(hwndListFormats, LB_ADDSTRING, 0, (LPARAM)buf);
  247.             if (idx != LB_ERR)
  248.                 SendMessage(hwndListFormats, LB_SETITEMDATA, idx, (LPARAM)pFormat);
  249.         }
  250.  
  251.         pFormat = pFormat_next;
  252.     }
  253. }
  254.  
  255. static BOOL CALLBACK AudioChooseCompressionDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) {
  256.     ACMChooserData *thisPtr = (ACMChooserData *)GetWindowLong(hdlg, DWL_USER);
  257.  
  258.     switch(msg) {
  259.     case WM_INITDIALOG:
  260.         {
  261.             ACMEnumeratorData aed;
  262.             int idx;
  263.             INT tabs[1];
  264.  
  265.             thisPtr = (ACMChooserData *)lParam;
  266.             SetWindowLong(hdlg, DWL_USER, lParam);
  267.  
  268.             tabs[0] = 140;
  269.  
  270.             SendDlgItemMessage(hdlg, IDC_FORMAT, LB_SETTABSTOPS, 1, (LPARAM)tabs);
  271.  
  272.             acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &aed.cbwfex);
  273.  
  274.             aed.pwfex = (WAVEFORMATEX *)allocmem(aed.cbwfex);
  275.             aed.pwfexSelect = thisPtr->pwfex;
  276.             aed.pwfexSrc = thisPtr->pwfexSrc;
  277.             aed.pTagSelect = NULL;
  278.             aed.pFormatSelect = NULL;
  279.  
  280.             if (!aed.pwfex) {
  281.                 EndDialog(hdlg, 0);
  282.                 return FALSE;
  283.             }
  284.  
  285.             aed.hwndDriverList = GetDlgItem(hdlg, IDC_DRIVER);
  286.  
  287.             acmDriverEnum(ACMDriverEnumerator, (DWORD)&aed, ACM_DRIVERENUMF_NOLOCAL);
  288.  
  289.             freemem(aed.pwfex);
  290.  
  291.             // This has to go last, because some version of DivX audio come up
  292.             // with a blank name. #*$&@*#$^)&@*#^@$
  293.  
  294.             idx = SendDlgItemMessage(hdlg, IDC_DRIVER, LB_INSERTSTRING, 0, (LPARAM)"<No compression (PCM)>");
  295.  
  296.             if (idx >= 0)
  297.                 SendDlgItemMessage(hdlg, IDC_DRIVER, LB_SETITEMDATA, idx, NULL);
  298.  
  299.  
  300.             if (!aed.pTagSelect) {
  301.                 SendMessage(aed.hwndDriverList, LB_SETCURSEL, 0, 0);
  302.             } else {
  303.                 int cnt, i;
  304.                 HWND hwndItem;
  305.                 ACMTagEntry *pTag;
  306.                 ACMFormatEntry *pFormat;
  307.  
  308.                 hwndItem = GetDlgItem(hdlg, IDC_DRIVER);
  309.                 cnt = SendMessage(hwndItem, LB_GETCOUNT, 0, 0);
  310.  
  311.                 for(i=0; i<cnt; i++) {
  312.                     pTag = (ACMTagEntry *)SendMessage(hwndItem, LB_GETITEMDATA, i, 0);
  313.  
  314.                     if (pTag == aed.pTagSelect) {
  315.                         SendMessage(hwndItem, LB_SETCURSEL, i, 0);
  316.                         AudioChooseShowFormats(hdlg, pTag, false);
  317.  
  318.                         hwndItem = GetDlgItem(hdlg, IDC_FORMAT);
  319.                         cnt = SendMessage(hwndItem, LB_GETCOUNT, 0, 0);
  320.  
  321.                         for(i=0; i<cnt; i++) {
  322.                             pFormat = (ACMFormatEntry *)SendMessage(hwndItem, LB_GETITEMDATA, i, 0);
  323.  
  324.                             if (pFormat == aed.pFormatSelect) {
  325.                                 SendMessage(hwndItem, LB_SETCURSEL, i, 0);
  326.                                 break;
  327.                             }
  328.                         }
  329.                         break;
  330.                     }
  331.                 }
  332.             }
  333.  
  334.             EnableWindow(GetDlgItem(hdlg, IDC_SHOWALL), !!thisPtr->pwfexSrc);
  335.         }
  336.         return TRUE;
  337.  
  338.     case WM_DESTROY:
  339.         {
  340.             HWND hwndList = GetDlgItem(hdlg, IDC_FORMATTAG);
  341.             int cnt = SendMessage(hwndList, LB_GETCOUNT, 0, 0);
  342.             int i;
  343.  
  344.             for(i=0; i<cnt; i++) {
  345.                 ACMTagEntry *pTag = (ACMTagEntry *)SendMessage(hwndList, LB_GETITEMDATA, i, 0);
  346.  
  347.                 delete pTag;
  348.             }
  349.             
  350.         }
  351.         return TRUE;
  352.  
  353.     case WM_CLOSE:
  354.         EndDialog(hdlg, 0);
  355.         return TRUE;
  356.  
  357.     case WM_COMMAND:
  358.         switch(GetWindowLong((HWND)lParam, GWL_ID)) {
  359.         case IDOK:
  360.             {
  361.                 int idx = SendDlgItemMessage(hdlg, IDC_FORMAT, LB_GETCURSEL, 0, 0);
  362.  
  363.                 if (idx < 0) {
  364.                     thisPtr->pwfex = NULL;
  365.                 } else {
  366.                     ACMFormatEntry *pFormat = (ACMFormatEntry *)SendDlgItemMessage(hdlg, IDC_FORMAT, LB_GETITEMDATA, idx, 0);
  367.  
  368.                     thisPtr->pwfex = pFormat->pwfex;
  369.                     pFormat->pwfex = NULL;
  370.                 }
  371.             }
  372.             EndDialog(hdlg, 1);
  373.             return TRUE;
  374.         case IDCANCEL:
  375.             EndDialog(hdlg, 0);
  376.             return TRUE;
  377.  
  378.         case IDC_FORMATTAG:
  379.             switch(HIWORD(wParam)) {
  380.             case LBN_SELCHANGE:
  381. redisplay_formats:
  382.                 {
  383.                     int idx = SendMessage((HWND)lParam, LB_GETCURSEL, 0, 0);
  384.  
  385.                     if (idx < 0) {
  386.                         AudioChooseShowFormats(hdlg, NULL, false);
  387.                         return TRUE;
  388.                     }
  389.  
  390.                     ACMTagEntry *pTag = (ACMTagEntry *)SendMessage((HWND)lParam, LB_GETITEMDATA, idx, 0);
  391.  
  392.                     AudioChooseShowFormats(hdlg, pTag, !IsDlgButtonChecked(hdlg, IDC_SHOWALL));
  393.  
  394.                 }
  395.                 return TRUE;
  396.             }
  397.             break;
  398.         case IDC_FORMAT:
  399.             switch(HIWORD(wParam)) {
  400.             case LBN_SELCHANGE:
  401.                 {
  402.                     int idx = SendMessage((HWND)lParam, LB_GETCURSEL, 0, 0);
  403.  
  404.                     if (idx < 0) {
  405.                         if (!SendDlgItemMessage(hdlg, IDC_FORMATTAG, LB_GETCURSEL, 0, 0))
  406.                             AudioChooseDisplaySpecs(hdlg, thisPtr->pwfexSrc);
  407.                         else
  408.                             AudioChooseDisplaySpecs(hdlg, NULL);
  409.                         return TRUE;
  410.                     }
  411.  
  412.                     ACMFormatEntry *pFormat = (ACMFormatEntry *)SendMessage((HWND)lParam, LB_GETITEMDATA, idx, 0);
  413.  
  414.                     AudioChooseDisplaySpecs(hdlg, pFormat->pwfex);
  415.                 }
  416.                 return TRUE;
  417.             }
  418.             break;
  419.         case IDC_SHOWALL:
  420.  
  421.             // Yeah, yeah...
  422.  
  423.             if (HIWORD(wParam) == BN_CLICKED) {
  424.                 lParam = (LPARAM)GetDlgItem(hdlg, IDC_FORMATTAG);
  425.                 goto redisplay_formats;
  426.             }
  427.  
  428.             break;
  429.         }
  430.         return TRUE;
  431.     }
  432.  
  433.     return FALSE;
  434. }
  435.  
  436. WAVEFORMATEX *AudioChooseCompressor(HWND hwndParent, WAVEFORMATEX *pwfexOld, WAVEFORMATEX *pwfexSrc) {
  437.     ACMChooserData data;
  438.  
  439.     data.pwfex = pwfexOld;
  440.     data.pwfexSrc = pwfexSrc;
  441.  
  442.     if (!DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_AUDIOCOMPRESSION), hwndParent, AudioChooseCompressionDlgProc, (LPARAM)&data))
  443.         return pwfexOld;
  444.     else {
  445.         if (pwfexOld)
  446.             freemem(pwfexOld);
  447.  
  448.         return data.pwfex;
  449.     }
  450. }
  451.